from common.exception import AuthorizationException
from google.appengine.api import taskqueue
from google.appengine.ext import db
from google.appengine.ext.webapp import RequestHandler, template
from google.appengine.runtime import DeadlineExceededError
from model.system_key_value_pair import SystemKeyValuePair
from model.link import Link
import common.twitter_util as twitter_util
import handler.config as config
import logging
import re
import time
import tweepy

class PollerTask(RequestHandler):
    def post(self):
        skip_old_updates = (self.request.get('skip_old_updates') == 'True')
        since_id = SystemKeyValuePair.get('feed_since_id').value
        if skip_old_updates:
            since_id = 0
        poller_version_str = self.request.get('poller_version')
        if len(poller_version_str) == 0:
            poller_version_str = '0'
        poller_version = int(self.request.get('poller_version'))
        logging.info('params: skip old updates: %s, poller version: %d'
                     % (skip_old_updates, poller_version))
        start = time.time() 
        
        try:
            api = self.__get_api()
        except AuthorizationException, e:
            logging.error(e)
            return
        
        try:
            while True:
                if not self.__is_version_current(poller_version):
                    return
                since_id = self.__poll_and_process(api, since_id)
                time.sleep(11)
        except DeadlineExceededError, e: 
            logging.warning('timed out after %f seconds'
                            % (time.time() - start))
            taskqueue.add(url='/task/poller',
                      queue_name='poller', 
                      params={'skip_old_updates': False,
                              'poller_version': poller_version})
       
            
    def __is_version_current(self, version):
        current_version = SystemKeyValuePair.get('poller').value
        if version != current_version:
            logging.warning('Poller has been restarted. My version: %d, '
                            'current version: %d'
                            % (version, current_version))
            return False
        else:
            return True
        
    def __poll_and_process(self, api, since_id):
        logging.info('polling, since_id=%d', since_id)
        statuses = None
        try:
            if since_id == 0:        
                statuses = api.friends_timeline(count=200)
            else:
                statuses = api.friends_timeline(count=200, since_id=since_id)
        except tweepy.TweepError, e:
            logging.warning(e)
            return since_id 
        
        for status in statuses:
            self.__process(status)
        
        if len(statuses) > 0:
            since_id =  statuses[0].id
            logging.debug('Update feed_since_id to %d', since_id)
            SystemKeyValuePair.set('feed_since_id', since_id)
        return since_id

    def __get_api(self):
        app_auth_handler = twitter_util.get_app_auth_handler(self.request.url)
        api = tweepy.API(auth_handler=app_auth_handler, secure=True, retry_count=3)
        return api
    
    def __process(self, status):
        try:
            if not self.__should_process(status):
                logging.info('Skips processing status for id=%d, text=%s, screen_name=%s'
                             % (status.id, status.text, status.user.screen_name))
            else:
                logging.info('Processing status for id=%d, text=%s, screen_name=%s'
                             % (status.id, status.text, status.user.screen_name))
                app_auth_handler = twitter_util.get_auth_handler(
                    status.user.screen_name, self.request.url)
                api = tweepy.API(auth_handler=app_auth_handler, secure=True, retry_count=3)
                new_status_text = self.__get_new_status_text(status)
                new_status = api.update_status(new_status_text)
                api.destroy_status(id=status.id)
                Link.insert(status.text, 
                            new_status.text,
                            int(status.id),
                            int(new_status.id))
                logging.info('Updated status for id=%d, text=%s, screen_name=%s'
                             % (status.id, status.text, status.user.screen_name))    
        except Exception, e:
            logging.warning(e)
            
    def __should_process(self, status):
        not_posted_by_app = not Link.get_by_updated_status_id(int(status.id))
        not_app = (status.user.screen_name != 
                   config.get_app_twitter_account(self.request.url))
        links = re.findall(r'https?://[^ ]+', status.text)
        has_link = len(links) > 0
        return not_posted_by_app and not_app and has_link
    
    def __get_new_status_text(self, status):
        return '"%s"' % status.text
           
                    
                